//正常判断类型的时候，可以通过A extends B，判断A是B的字类型
//条件分发：分发特性是默认开启的

//开始分发特性，需要满足一下3个条件
//1.A类型是通过泛型传入的
//2.A类型是联合类型才会进行分发
//3.泛型参数A必须是完全裸露的才会进行分发
//常用：
//keyof 取k
//typeof 取类型的
//索引查询[]
//in 循环的
//extends 条件判断
interface Fish {
    name: "鱼";
  }
  interface Water {
    name: "水";
  }
  interface Bird {
    name: "鸟";
  }
  interface Sky {
    name: "天";
  }
  //------------------------------分发的基本使用-----------------------------
  //Bird  extends Bird  false=>Water
  //Fish  extends Bird  false=>Water
  type C0 = Bird | Fish extends Bird ? Sky : Water; //不满足条件，不会分发=>Water
  type C1<T> = T extends Bird ? Sky : Water; //T此刻满处上面3个条件，会进行分发
  type C2<T, U> = T extends U ? true : false;
  type R1 = C1<Bird | Fish>; //=>Water | Sky，看似没有问题，其实有问题
  //1 extends 1 =>true
  //2 extends 1=>false
  //ture和false ，结果就是boolean
  type R2 = C2<1 | 2, 1>; //boolean，正确的结果应该是false
  //什么事分发：分发就是挨个比较
  //不想分发；就是将结果运算后再比较
  //1、不可以分发-{}
  type C3<T, U> = T & {} extends U ? true : false;
  type R3 = C3<1 | 2, 1>; //false
  //2、不可以分发-[]
  type C4<T, U> = [T] extends [U] ? true : false;
  type R4 = C4<1 | 2, 1>; //false
  //never 类型判断
  type IsNever<T> = T extends never ? true : false;
  type R5 = IsNever<never>; //=>never这样比较时无法返回正确的结果
  type C6<T> = [T] extends [never] ? true : false;
  type R6 = C6<never>; //=>true这样比较时无法返回正确的结果
  //--------------------分发：根据分发实现内置方法-------------------------
  //-----------------------内置1:Extract:从某个里面，【提取】指定内容-（交集）-----------------------
  type de = Extract<1 | 4, 4 | 3>; //提取
  type MyExtract<T, U> = T extends U ? T : never;
  type Extract1 = MyExtract<1 | 4, 4 | 3>; //提取
  
  //-----------------------内置2:Exclude：从某个里面，【排除】指定内容-（差集）------------------------
  
  type MyExclude<T, U> = T extends U ? never : T;
  type de1 = Exclude<1 | 4 | 5, 4 | 1>; //提取
  
  type de2 = MyExclude<1 | 4 | 5, 4 | 1>; //提取
  
  //-----------------------内置3:NonNullable：从某个里面，【移除】null/undefined-非空判断（）-----------------------
  type DD = NonNullable<1 | 2 | null | undefined>;
  //第一种实现方式
  type MyNonNullable1<T> = T extends null | undefined ? never : T;
  type DD1 = MyNonNullable1<1 | 2 | null | undefined>;
  
  //第二种实现方式
  
  type MyNonNullable2<T> = T & {};
  type DD2 = MyNonNullable1<1 | 2 | null | undefined>;
  
  //---------------------总结：可以求联合类型的交集、差集：Extract、Exclude，后续可以求对象属性的交集、差集-----------------------
  
  //-----------------------infer类型推断-----------------------
  //infer:可以在条件类型中提取类型的一部分，在使用的时候，想要获取什么类型就把它写在什么地方，加一个变量来自动推导，类型推倒都是基于位置的。
  //使用infer首先要创造一个条件才可以
  //泛型约束的目的是限制泛型传入的，后面的条件是逻辑
  //-----------------------内置4:ReturnType获取函数的返回值类型-----------------------
  function getObj(name: string, age: number) {
    return {
      name,
      age,
    };
  }
  const obj = {};
  type IFunc = (...arg: any) => any;
  type DD12 = ReturnType<typeof getObj>;
  type MyReturnType<T extends IFunc> = T extends (...arg: any[]) => infer P
    ? P
    : never; //infer P :获取返回值的类型
  type DD123 = MyReturnType<typeof getObj>;
  
  //-----------------------内置5:ReturnType获取函数的返回值类型-----------------------
  type P1 = Parameters<typeof getObj>;
  type MyParameters<T extends IFunc> = T extends (...arg: infer P) => any
    ? P
    : never; //infer P :获取参数的类型
  type P2 = MyParameters<typeof getObj>;
  
  //-----------------------内置5:InstanceType获取构造函数的实例-----------------------
  abstract class A {
    constructor(name: string, age: number) {}
  }
  type I1 = InstanceType<typeof A>;
  type MyInstanceType<T extends abstract new (...arg: any[]) => any> =
    T extends abstract new (...arg: any[]) => infer R ? R : never; //abstract 防止class A抽象
  type I2 = MyInstanceType<typeof A>;
  //-----------------------内置5:ConstructorParameters获取类的参数-----------------------
  class B {
    constructor(name: string, age: number) {}
  }
  function creatInstance<T extends new (...args: any[]) => any>(
    target: T,
    ...args: ConstructorParameters<T>
  ): InstanceType<T> {
    return new target(...args);
  }
  let r = creatInstance(B, "xh", 12);
  
  //---------------------------------infer挑战--------------------------------
  //1、Swap：交换
  type Swap<T>=T extends [infer A1,infer A2] ? [A2,A1] : never;
  type S1=Swap<['xhm',12]>
  //2、Swap：头尾交换
  type SwapHeaderTail<T>=T extends [infer A1,...infer N,infer A2] ? [A2,...N,A1] : never;
  type S2=SwapHeaderTail<['xhm',1,2,3,4,5,12]>
  //3、Promise实现无线递归，通过infer来实现递归推倒
  type PromiseReturnVal<T>=T extends Promise<infer P> ?PromiseReturnVal<P> : T;
  type S3=PromiseReturnVal<Promise<Promise<Promise<100>>>>
  //4、将元祖转化为联合类型[string,number,boolean]
  type TupleArray=[string,boolean,number]
  //第一种方式，索引
  type T1=TupleArray[number]//=>string | number | boolean
  //第二种方式：infer
  type ElementUnion2<T>=T extends Array<infer E>? E : never;//根据位置推倒：[string,boolean,number]=[E]
  type T2=ElementUnion2<TupleArray>//=> string | number | boolean
  export {};
  
  //---------------------------------内置类型：Partial、Required、readonly--------------------------------
  interface IPerson{
      name:string
      age:number
      // address:string
  }
  //1、Partial：可选
  type MyPartial<T>={
      [K in keyof T]?:T[K]
  }
  const P1:MyPartial<IPerson>={
      name:'xhm'
  }
  //2、Required:必填
  type MyRequired<T>={
      [K in keyof T]-?:T[K]
  }
  
  const P2:MyRequired<MyPartial<IPerson>>={
      name:'xhm',
      age:3
  }
  
  //3、Readonly:只读
  type MyReadonly<T>={
     readonly [K in keyof T]:T[K]
  }
  const P3:MyReadonly<IPerson>={
      name:'xhm',
      age:23
  }
  //P3.name='fff' //不可以修改
  
  //4、可修改
  type Mutate<T>={
      -readonly [K in keyof T]:T[K]
   }
  
   const P4:Mutate<MyReadonly<IPerson>>={
      name:'xhm',
      age:23
  }
  P4.name='fff'//可以修改
  
  //---------------------------------内置类型：Pick、Omit，重构对象的接口，可以采用这个属性-------------------------------
  interface IPerson1{
      name:string
      age:number
      // address:string
  }
  //1、Omit：在很多属性中排除不需要的
  type OmitOerson=Omit<IPerson1,'name'>
  type MyOmit<T,K extends keyof T>=Pick<T,Exclude<keyof T,K>>//1、Exclude<keyof T,K>排除不需要的，Pick，选择需要的
  type MyOmitOerson=MyOmit<IPerson1,'name'>
  //映射类型，Omit+Pick和Exclude +Extrack，可以实现各种各样的类型
  function mixin<T,K>(a:T,b:K):Omit<K,keyof T> & T{
      return {...a,...b}
  }
  const m=mixin({a:1},{b:2})
  type Computed<T>={
      //通过这种创建一个新对象的方式，更直观的查看结果
      [K in keyof T]:T[K]
  }
  type SS=Computed<typeof m>
  
  //---------------------------------内置类型：Record，只要key value的格式，可以采用Record-------------------------------
  type P6=Record<string,any>
  //一些映射类型采用Record，更合理一些
  type MyRecode<K extends keyof any,V>={[P in K]:V}//K是联合类型
  //任意接口
  type P7=MyRecode<string,any>
  
  //实现map函数
  function map<T extends keyof any,K,R>(
      obj:Record<T  ,K>,
      callback:(value:K,key:T)=>R){
          let result={} as Record<T,R>
       for (const key in obj) {
          result[key]=callback(obj[key],key)
       }
       return result;
  }
  let res=map({a:1,b:2},(value,key)=>{
      return {name:'ch'}
  })